/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package TimeRecording.reporting;

import TimeRecording.business.DateRange;
import TimeRecording.enums.HolidayAdjustmentStatus;
import TimeRecording.tables.Employee;
import TimeRecording.tables.HolidayAdjustment;
import TimeRecording.tables.HolidayRequest;
import TimeRecording.tables.SicknessReport;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.util.JRLoader;
import net.sf.jasperreports.view.JasperViewer;

/**
 *
 * @author david
 */
public class EmployeeSummaryReport {

    private final static String REPORT_NAME =
            "/reports/employee/EmployeeDetailsReport.jasper";
    
    private final static Logger LOGGER =
            Logger.getLogger(EmployeeSummaryReport.class.getName());
    
    // <editor-fold defaultstate="collapsed" desc="AbsenceDetail">
    public static class AbsenceDetail {
        
        private Date startDate;
        private Date endDate;

        private String startPart;
        private String endPart;
        
        private String status;

        public AbsenceDetail() {
        }
        
        public AbsenceDetail(Date startDate, Date endDate,
                String startPart, String endPart, String status) {
            
            this.startDate = startDate;
            this.endDate = endDate;
            this.startPart = startPart;
            this.endPart = endPart;
            this.status = status;
        }

        public Date getEndDate() {
            return endDate;
        }

        public void setEndDate(Date endDate) {
            this.endDate = endDate;
        }

        public Date getStartDate() {
            return startDate;
        }

        public void setStartDate(Date startDate) {
            this.startDate = startDate;
        }

        public String getEndPart() {
            return endPart;
        }

        public void setEndPart(String endPart) {
            this.endPart = endPart;
        }

        public String getStartPart() {
            return startPart;
        }

        public void setStartPart(String startPart) {
            this.startPart = startPart;
        }

        public String getStatus() {
            return status;
        }

        public void setStatus(String status) {
            this.status = status;
        }
    } // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="GrantDetail">
    public class GrantDetail {

        private Date date;
        private Double hours;
        private String type;
        private HolidayAdjustmentStatus status;

        public GrantDetail() {
        }

        public GrantDetail(Date date, Double hours, String type,
                HolidayAdjustmentStatus status) {

            this.date = date;
            this.hours = hours;
            this.type = type;
            this.status = status;
        }

        public Date getDate() {
            return date;
        }

        public void setDate(Date date) {
            this.date = date;
        }

        public Double getHours() {
            return hours;
        }

        public void setHours(Double hours) {
            this.hours = hours;
        }

        public HolidayAdjustmentStatus getStatus() {
            return status;
        }

        public void setStatus(HolidayAdjustmentStatus status) {
            this.status = status;
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }
    } // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="EmployeeDetail">
    public static class EmployeeDetail {
        
        private String name;

        private double leaveGranted;
        private double leaveApproved;
        private double leaveTaken;
        private double leaveRemaining;
        private double leaveNotYetApproved;
        private double sicknessTaken;

        private JRBeanCollectionDataSource holidays;
        private JRBeanCollectionDataSource adjustments;
        private JRBeanCollectionDataSource sickness;

        public EmployeeDetail() {
        }

        public EmployeeDetail(String name,
                JRBeanCollectionDataSource holidays,
                JRBeanCollectionDataSource adjustments,
                JRBeanCollectionDataSource sickness,
                double leaveGranted,
                double leaveApproved,
                double leaveTaken,
                double leaveRemaining,
                double leaveNotYetApproved,
                double sicknessTaken) {

            this.name = name;
            this.holidays = holidays;
            this.adjustments = adjustments;
            this.sickness = sickness;
            this.leaveGranted = leaveGranted;
            this.leaveApproved = leaveApproved;
            this.leaveTaken = leaveTaken;
            this.leaveRemaining = leaveRemaining;
            this.leaveNotYetApproved = leaveNotYetApproved;
            this.sicknessTaken = sicknessTaken;
        }

        public JRBeanCollectionDataSource getHolidays() {
            return holidays;
        }

        public void setHolidays(JRBeanCollectionDataSource holidays) {
            this.holidays = holidays;
        }

        public JRBeanCollectionDataSource getAdjustments() {
            return adjustments;
        }

        public void setAdjustments(JRBeanCollectionDataSource adjustments) {
            this.adjustments = adjustments;
        }

        public JRBeanCollectionDataSource getSickness() {
            return sickness;
        }

        public void setSickness(JRBeanCollectionDataSource sickness) {
            this.sickness = sickness;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public double getLeaveApproved() {
            return leaveApproved;
        }

        public void setLeaveApproved(double leaveApproved) {
            this.leaveApproved = leaveApproved;
        }

        public double getLeaveGranted() {
            return leaveGranted;
        }

        public void setLeaveGranted(double leaveGranted) {
            this.leaveGranted = leaveGranted;
        }

        public double getLeaveNotYetApproved() {
            return leaveNotYetApproved;
        }

        public void setLeaveNotYetApproved(double leaveNotYetApproved) {
            this.leaveNotYetApproved = leaveNotYetApproved;
        }

        public double getLeaveRemaining() {
            return leaveRemaining;
        }

        public void setLeaveRemaining(double leaveRemaining) {
            this.leaveRemaining = leaveRemaining;
        }

        public double getLeaveTaken() {
            return leaveTaken;
        }

        public void setLeaveTaken(double leaveTaken) {
            this.leaveTaken = leaveTaken;
        }

        public double getSicknessTaken() {
            return sicknessTaken;
        }

        public void setSicknessTaken(double sicknessTaken) {
            this.sicknessTaken = sicknessTaken;
        }
    } // </editor-fold>

    @SuppressWarnings("unchecked")
    public void viewReport(EntityManager entityManager, DateRange dateRange) {

        LOGGER.finer("viewReport (all employees)");
        
        List<Employee> employees = Employee.getActiveEmployees(entityManager);
        viewReport(employees, dateRange);
    }

    @SuppressWarnings("unchecked")
    public void viewReport(Collection<Employee> employeesIn, DateRange dateRange) {

        LOGGER.finer("viewReport (specific employees)");

        ArrayList<EmployeeDetail> employeesOut =
                new ArrayList<EmployeeDetail>();

        for (Employee employeeIn : employeesIn) {

            EmployeeDetail employeeOut = new EmployeeDetail();

            employeeOut.setName(employeeIn.getFriendlyName());

            employeeOut.setLeaveGranted(employeeIn.
                    getWorkingPatternsMaster().getAnnualLeaveTaken());
            employeeOut.setLeaveApproved(employeeIn.
                    getWorkingPatternsMaster().getAnnualLeaveApproved());
            employeeOut.setLeaveTaken(employeeIn.
                    getWorkingPatternsMaster().getAnnualLeaveTaken());
            employeeOut.setLeaveRemaining(employeeIn.
                    getWorkingPatternsMaster().getAnnualLeaveRemaining());
            employeeOut.setLeaveNotYetApproved(employeeIn.
                    getWorkingPatternsMaster().getAnnualLeaveUnapproved());
            employeeOut.setSicknessTaken(employeeIn.getSickness());

            employeeOut.setHolidays(new JRBeanCollectionDataSource(
                    processHolidayRequests(employeeIn, dateRange)));

            employeeOut.setAdjustments(new JRBeanCollectionDataSource(
                    processHolidayGrants(employeeIn, dateRange)));

            employeeOut.setSickness(new JRBeanCollectionDataSource(
                    processSicknessReports(employeeIn, dateRange)));

            employeesOut.add(employeeOut);
        }

        try {
            JasperReport template = (JasperReport)JRLoader.loadObject(
                    getClass().getResource(REPORT_NAME));

            JasperPrint report = JasperFillManager.fillReport(
                    template, new ReportingUtilities().getBasicParameters(),
                    new JRBeanCollectionDataSource(employeesOut));

            JasperViewer.viewReport(report, false);

        } catch (JRException ex) {
            Logger.getLogger(EmployeeSummaryReport.class.getName())
                    .log(Level.SEVERE, null, ex);
        }
    }

    // <editor-fold defaultstate="collapsed" desc="processHolidayRequests">
    /**
     * Extracts the holiday records from the employee bean for the given date
     * range and throws them into a "report friendly" collection of absence
     * details.
     *
     * @param employee the employee details to interrogate
     * @param dateRange the inclusive date range for holiday requests
     * @return a collection of report friendly absence reports
     */
    private Collection<AbsenceDetail> processHolidayRequests(
            Employee employee, DateRange dateRange) {

        Collection<HolidayRequest> requestsIn = employee.getHolidayRequests();
        ArrayList<AbsenceDetail> requestsOut = new ArrayList<AbsenceDetail>();

        for (HolidayRequest requestIn : requestsIn) {

            // Skip any holidays outside of the date range
            if ((requestIn.getFirstDayOfHoliday() != null &&
                    requestIn.getFirstDayOfHoliday().after(dateRange.getToDate())) ||
                    (requestIn.getLastDayOfHoliday() != null &&
                    requestIn.getLastDayOfHoliday().before(dateRange.getFromDate()))) {
                continue;
            }

            AbsenceDetail requestOut = new AbsenceDetail(
                    requestIn.getFirstDayOfHoliday(),
                    requestIn.getLastDayOfHoliday(),
                    requestIn.getFirstDayPart().toString(),
                    requestIn.getLastDayPart().toString(),
                    requestIn.getStatus().toString());

            requestsOut.add(requestOut);
        }

        return requestsOut;
    } // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="processHolidayGrants">
    /**
     * Extracts the holiday grants/adjustments from the employee bean for the
     * given date range and throws them into a "report friendly" collection of
     * grant details.
     *
     * @param employee the employee details to interrogate
     * @param dateRange the inclusive date range for holiday grants
     * @return a collection of report friendly grant details
     */
    private Collection<GrantDetail> processHolidayGrants(
            Employee employee, DateRange dateRange) {
        
        Collection<HolidayAdjustment> grantsIn = employee.getHolidayAdjustments();
        ArrayList<GrantDetail> grantsOut = new ArrayList<GrantDetail>();
        
        for (HolidayAdjustment grantIn : grantsIn) {
            
            // Skip any gramts outside of the date range
            if (grantIn.getAdjustmentDate() == null ||
                    grantIn.getAdjustmentDate().before(dateRange.getFromDate()) ||
                    grantIn.getAdjustmentDate().after(dateRange.getToDate())) {
                continue;
            }
            
            GrantDetail grantOut = new GrantDetail(
                    grantIn.getAdjustmentDate(),
                    grantIn.getHoursAdjusted(),
                    grantIn.getAdjustmentType().toString(),
                    grantIn.getStatus());

            grantsOut.add(grantOut);
        }

        return grantsOut;
    } // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="processSicknessReports">
    /**
     * Extracts the sickness reports from the employee bean for the given date
     *  range and throws them into a "report friendly" collection of absence
     * reports.
     *
     * @param employee the employee details to interrogate
     * @param dateRange the inclusive date range for sickness reports
     * @return a collection of report friendly sickness reports
     */
    private Collection<AbsenceDetail> processSicknessReports(
            Employee employee, DateRange dateRange) {

        Collection<SicknessReport> reportsIn = employee.getSicknessReports();
        ArrayList<AbsenceDetail> reportsOut = new ArrayList<AbsenceDetail>();

        for (SicknessReport reportIn : reportsIn) {

            // Skip any holidays outside of the date range
            if ((reportIn.getFirstDayOfSickness() != null &&
                    reportIn.getFirstDayOfSickness().after(dateRange.getToDate())) ||
                    (reportIn.getLastDayOfSickness() != null &&
                    reportIn.getLastDayOfSickness().before(dateRange.getFromDate()))) {
                continue;
            }

            AbsenceDetail reportOut = new AbsenceDetail(
                    reportIn.getFirstDayOfSickness(),
                    reportIn.getLastDayOfSickness(),
                    reportIn.getFirstDayPart().toString(),
                    reportIn.getLastDayPart().toString(),
                    reportIn.getStatus().toString());

            reportsOut.add(reportOut);
        }

        return reportsOut;
    } // </editor-fold>
}
